package com.core.config;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;

/**
 * @Author: 孙常胜
 * @CreateTime: 2021/7/9 10:51
 * @Description:
 */
@Log4j2
@Component
public class Server {
    private static int port = 1182;

    /**
     * 启动netty服务端
     */
    public void startServer() {
        //netty通过ServerBootstrap启动服务端
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //定义两个线程组，用来处理客户端通道的accept和读写事件
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        serverBootstrap.group(bossGroup, workerGroup);
        //绑定服务端通道
        serverBootstrap.channel(NioServerSocketChannel.class);
        //服务端处理客户端连接请求是按顺序处理的，所以同一时间只能处理一个客户端连接
        //多个客户端来的时候，服务端将不能处理的客户端连接请求放在队列中等待处理，backlog参数指定了队列的大小。
        serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
        //绑定handler，处理读写事件，ChannelInitializer是给通道初始化
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                //解码器，接收的数据进行解码，一定要加在自定义handler的上面
                //StringDecoder会将数据转字符串，避免重复[将获取的msg转为Bytebuf对象，然后将ByteBuf转为byte数组，最后使用类型转换将byte数组转为字符串]的操作
                socketChannel.pipeline().addLast(new StringDecoder());
                //编码格式
                socketChannel.pipeline().addLast(new StringEncoder(Charset.forName("GBK")));
                //解码格式
                socketChannel.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8")));
                //处理数据
                socketChannel.pipeline().addLast(new ServerHandler());
            }
        });
        try {
            //第4步绑定端口
            ChannelFuture future = serverBootstrap.bind(port).sync();
            log.info("绑定端口成功，端口号为：{}", port);
            //当通道关闭了，就继续往下走
            future.channel().closeFuture().sync();
        } catch (Exception E) {
            E.printStackTrace();
        } finally {
            //netty优雅停机
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
